import java.io.BufferedReader;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * A database of DVD entries. Keeps transaction information.
 */
public class DVDDatabase {

	/*Maps DVD names to DVD entries*/
	private Map<String, DVDEntry> entries;
	
	/*Stores transactions for output to file*/
	private List<DVDTransaction> transactions;

	/**
	 * Initialize a DVD database with a list of entries.
	 * The list is used to create a mapping of DVD name -> entry
	 */
	public DVDDatabase (List<DVDEntry> entries){
		this.entries = new HashMap<String, DVDEntry>();
		this.transactions = new ArrayList<DVDTransaction>();
		for (DVDEntry dvd : entries){
			this.entries.put(dvd.getName(), dvd);
		}
	}
	
	/**
	 * Creates a DVD database out of a DVD file
	 * @param filename name of the DVD file
	 * @return a new DVD database
	 * @throws IOException
	 */
	static DVDDatabase createDVDDatabase(String filename) throws IOException{
		BufferedReader br = new BufferedReader(new FileReader(filename));
		List<DVDEntry> entries = new ArrayList<DVDEntry>();
		while (true){
			String s = br.readLine();
			if (s == null) break;
			DVDEntry newEntry = DVDEntry.createEntryFromLine(s);
			if (newEntry == null) return null;
			entries.add(newEntry);
			
		} 
		return new DVDDatabase(entries);
	}
	
	/**
	 * Retrieve an iterable list of DVD entries
	 * @return a new iterable list
	 */
	public List<DVDEntry> entryList(){
		return new ArrayList<DVDEntry>(entries.values());
	}
	
	/**
	 * Remove DVD entry from the database
	 * @param dvdname the DVD name to remove
	 * @return whether an object was removed
	 */
	public boolean remove(String dvdname){
		return entries.remove(dvdname) != null;
	}
	
	/**
	 * Insert a DVD entry into the database
	 * @param entry Entry to add
	 */
	public void addDVDEntry(DVDEntry entry){
		entries.put(entry.getName(),entry);
	}
	
	/**
	 * Return DVD entry object from the database
	 * @param dvdname the DVD name to fetch
	 * @return the DVD entry corresponding to name
	 */
	public DVDEntry getDVDEntry(String dvdname) {
		DVDEntry e = entries.get(dvdname);
		if(e == null) throw new InvalidDVDException("The DVD '"+dvdname+"' is not available.");
		return e;
	}

	/**
	 * Check if DVD exists in database
	 * @param dvdname the DVD name to check
	 * @return whether the entry exists or not
	 */
	public boolean hasDVDEntry(String dvdname){
		return entries.containsKey(dvdname);
	}

	/**
	 * Store a transaction in the database
	 * @param t the transaction
	 */
	public void addTransaction(DVDTransaction t){
		transactions.add(t);
	}
	
	/**
	 * Create a transaction file detailing all the transactions processed
	 * @param file the location to save the produced the file
	 */
	public void toDVDTransactionFile(String file) throws IOException{
		//Create a new transaction file, overwriting any existing files
		PrintWriter fw = new PrintWriter(new FileWriter(file, false));
		for (DVDTransaction transaction : transactions){
			fw.println(transaction.toTransactionString());
		}
		fw.close();
	}
}
